package com.vhall.component.framework.common.utils;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;

/**
 * @author yuanzh
 */
@Slf4j
public class AesUtil {

    private AesUtil() {
        throw new IllegalStateException("Utility class");
    }

    private static final String KEY_ALGORITHM = "AES";

    private static final String CIPHER_PKCS7_ALGORITHM = "AES/CBC/PKCS7Padding";

    private static final String ENCRYPT_ERROR = "encrypt error";

    /**
     * ECB/PKCS7 加密
     *
     * @param value
     * @param secret
     * @param secretKey
     * @return
     */
    public static String encryptPKCS7(String value, byte[] secret, byte[] secretKey) {
        try {
            byte[] key = secret;
            byte[] iv = secretKey;
            byte[] encrypted = encrypt(StringUtils.getUTF8Bytes(value), key, iv, CIPHER_PKCS7_ALGORITHM);
            return Base64Coding.encode(encrypted);
        } catch (Exception e) {
            log.error(ENCRYPT_ERROR, e);
        }
        return null;
    }

    /**
     * ECB/PKCS7 加密
     *
     * @param value
     * @param secret
     * @param secretKey
     * @return
     */
    public static String encryptPKCS7(String value, String secret, String secretKey) {
        try {
            byte[] key = StringUtils.getUTF8Bytes(secret);
            byte[] iv = StringUtils.getUTF8Bytes(secretKey);
            byte[] encrypted = encrypt(StringUtils.getUTF8Bytes(value), key, iv, CIPHER_PKCS7_ALGORITHM);
            return Base64Coding.encode(encrypted);
        } catch (Exception e) {
            log.error(ENCRYPT_ERROR, e);
        }
        return null;
    }

    /**
     * ECB/PKCS7 解密
     *
     * @param value
     * @param secret
     * @param secretKey
     * @return
     */
    public static String decryptPKCS7(String value, String secret, String secretKey) {
        try {
            byte[] key = StringUtils.getUTF8Bytes(secret);
            byte[] iv = StringUtils.getUTF8Bytes(secretKey);
            byte[] encrypted1 = Base64Coding.decode(value);
            byte[] original = decrypt(encrypted1, key, iv, CIPHER_PKCS7_ALGORITHM);
            return StringUtils.getUTF8String(original);
        } catch (Exception e) {
            log.error("decryptPKCS7 error", e);
        }
        return null;
    }

    /**
     * ECB/PKCS7 解密
     *
     * @param value
     * @param secret
     * @param secretKey
     * @return
     */
    public static String decryptPKCS7(String value, byte[] secret, byte[] secretKey) {
        try {
            byte[] key = secret;
            byte[] iv = secretKey;
            // 先用base64解密
            byte[] encrypted1 = Base64Coding.decode(value);
            byte[] original = decrypt(encrypted1, key, iv, CIPHER_PKCS7_ALGORITHM);
            return StringUtils.getUTF8String(original);
        } catch (Exception e) {
            log.error("decryptPKCS7 error", e);
        }
        return null;
    }

    public static byte[] encrypt(byte[] content, byte[] secret, byte[] secretKey, String cipherType) {
        try {
            byte[] key = secret;
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(cipherType, "BC");
            if (CollectionUtils.isNotEmpty(secretKey)) {
                AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
                parameters.init(new IvParameterSpec(secretKey));
                cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, parameters);
            }
            return cipher.doFinal(content);
        } catch (Exception e) {
            log.error(ENCRYPT_ERROR, e);
        }
        return new byte[0];
    }

    /**
     * 解密
     *
     * @param content
     * @param secret
     * @param secretKey
     * @param cipherType
     * @return
     */
    public static byte[] decrypt(byte[] content, byte[] secret, byte[] secretKey, String cipherType) {
        try {
            byte[] key = secret;
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, KEY_ALGORITHM);
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance(cipherType, "BC");
            if (CollectionUtils.isNotEmpty(secretKey)) {
                AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
                parameters.init(new IvParameterSpec(secretKey));
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, parameters);
            }
            return cipher.doFinal(content);
        } catch (Exception e) {
            log.error("decrypt error", e);
        }
        return new byte[0];
    }

}
